package cn.jimmie.learn.viewArt.ball;

import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;

/**
 * function : MVP 中的P层, 用于视图的逻辑处理
 *
 * <p> Create Time: 2019年01月01日 09:18 </p>
 * <p> @author Jimmie.Qian  </p>
 */
class AssistScrollerProcessor implements AssistScrollerRunnable.OnScrollerListener {
    private static final int AUTO_LOCK_TIME = 60 * 1000;
    // 最小滑动单位判断
    private final int TOUCH_SLOP;
    // 事件源
    private final EventSource mSource;
    // 动态滑动相关
    private final AssistScrollerRunnable mRunnable;
    // 手势处理相关
    private final GestureDetector mDetector;
    int downX, downY;
    // 浮球应该旋转的角度和百分比
    int angle;
    float pct;
    int o = AssistBallView.LEFT;
    // 各类坐标记录
    private int lastX, lastY;
    // touch事件是否被消费
    private boolean hasConsume;
    // 浮球是否被锁定了
    private boolean isLock;
    private boolean isTouchToEdge;
    private Runnable mAutoLock = new Runnable() {
        @Override
        public void run() {
            isLock = true;
            mSource.setLock(true);
            mSource.moveBy(0, 0);

        }
    };

    AssistScrollerProcessor(final EventSource source) {
        this.mSource = source;
        mRunnable = new AssistScrollerRunnable(source, this);
        TOUCH_SLOP = ViewConfiguration.get(source.getContext()).getScaledTouchSlop();

        mDetector = new GestureDetector(source.getContext(), new OnGestureListenerAdapter() {
            @Override
            public void onLongPress(MotionEvent e) {
                isLock = !isLock;
                source.onLongPress(isLock);
                moveToEdge();
            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                if (!isLock) {
                    moveToEdge();
                }
                if (isLock || !isHalfState())
                    source.onClick(isLock);
                hasConsume = true;
                return true;
            }
        });
    }

    /**
     * 用于资源释放
     */
    void release() {
        mRunnable.removeAllListeners();
        mSource.removeCallbacks(mAutoLock);
    }

    /**
     * 将浮球移动到边缘(贴边)
     */
    void moveToEdge() {
        mRunnable.moveToEdge();
        if (!isLock) mSource.postDelayed(mAutoLock, AUTO_LOCK_TIME);
    }

    /**
     * 根据浮球的坐标来判断浮球旋转的角度
     */
    void handleAngle(int x, int y) {
        int size = mSource.getSize();
        float halfSize = size >> 1;

        angle = 0;
        pct = AssistBallView.NONE_PCT;
        // 正在向上帖 目标转180度
        if (y <= 0) {
            o = AssistBallView.TOP;
            angle = (int) (y * 180f / halfSize);
            pct = Math.abs(angle / 180f);
        }
        // 向下贴
        else if (y >= mSource.H() - size) {
            o = AssistBallView.BOTTOM;
            float t = y - mSource.H() + size;
            pct = t / halfSize;
        }
        // 正在向左边贴
        else if (x <= 0 && y < mSource.H() * 5 / 6) {
            o = AssistBallView.LEFT;
            angle = (int) (-x * 90f / halfSize);
            pct = Math.abs(angle / 90f);
        }
        // 正在向右边贴
        else if (x >= mSource.W() - size) {
            o = AssistBallView.RIGHT;
            angle = (int) ((x - mSource.W() - size) * -90f / halfSize);
            float t = x - mSource.W() + size;
            pct = t / halfSize;
        }
    }

    /**
     * 处理触摸事件
     */
    boolean handleTouchEvent(MotionEvent event) {
        // 按下去的时候, 设置为未消费
        if (!isLock && event.getAction() == MotionEvent.ACTION_DOWN) {
            mSource.removeCallbacks(mAutoLock);
            mRunnable.releaseResource();

            mSource.onHideChanged(false);
            downX = lastX = (int) event.getRawX();
            downY = lastY = (int) event.getRawY();
            hasConsume = false;
        }
        // 判断是否消费 点击和长按事件 和锁定事件
        mDetector.onTouchEvent(event);
        hasConsume = hasConsume || isLock;
        if (hasConsume) return true;

        // 移动和抬起事件
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            int x = (int) event.getRawX();
            int y = (int) event.getRawY();
            int deltaX = x - lastX;
            int deltaY = y - lastY;
            lastX = x;
            lastY = y;
            boolean move = Math.max(Math.abs(x - downX), Math.abs(y - downY)) > TOUCH_SLOP;
            // 判断滑动距离和是否超出边界
            if (move && !isOutOfEdge()) {
                mSource.moveBy(deltaX, deltaY);
                int xx = mSource.lx();
                int yy = mSource.ly();
                mSource.onActionMove(xx, yy);
            }
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            isTouchToEdge = true;
            mSource.onActionUp();
            moveToEdge();
        }
        return true;
    }

    /**
     * 判断是否超出了边界, 超出则不能再继续移动
     */
    private boolean isOutOfEdge() {
        int x = mSource.lx();
        int y = mSource.ly();
        int halfSize = mSource.getSize() / 2;
        return x < -(halfSize) || x > mSource.W() + halfSize || y < -(halfSize) || y > mSource.H() + halfSize;
    }

    private boolean isHalfState() {
        int x = mSource.lx();
        int y = mSource.ly();
        int size = mSource.getSize() / 4;
        return x < -size
            || x > mSource.W() - size * 3
            || y < -size
            || y > mSource.H() - size * 3;
    }

    @Override
    public void onAttachedEdge() {
        if (isTouchToEdge) {
            mSource.onAttachedEdge();
            isTouchToEdge = false;
        }
    }
}
